// Test for the util::sexpression interface
// Copyright 2004 (C) Ralph Thomas

#include <util/sexpression.h>
#include <tests/testCore.h>

namespace util {
	class testSexpressionFromString : public test::basic {
	  public:
		const char* performTest() {
			//
			// check that the sexpression::fromString method detects
			// basic errors.
			//
			unsigned int ecode;
			if( (sexpression::fromString( "(", ecode ) != NULL) || (ecode != sexpression::kUnbalancedParens) )
				return "sexpression::fromString didn't return error for S-Expression \"(\"";
			if( (sexpression::fromString( "))", ecode ) != NULL) || (ecode != sexpression::kUnbalancedParens) )
				return "sexpression::fromString didn't return error for S-Expression \"))\"";
			if( (sexpression::fromString( "(()()()", ecode ) != NULL) || (ecode != sexpression::kUnbalancedParens) )
				return "sexpression::fromString didn't return error for S-Expression \"(()()()\"";
			if( sexpression::fromString( "(\"THIS IS)))", ecode ) != NULL )
				return "sexpression::fromString didn't return error for non-terminating string";
			if( sexpression::fromString( "(NIL\"STRING\")", ecode ) != NULL )
				return "sexpression::fromString didn't return error for bad atom";
			//
			// try some parsing that should succeed
			//
			sexpression* sexp = sexpression::fromString( "(765 \"STRING\" NIL)", ecode );
			if( !sexp ) return "sexpression::fromString returned failure when parsing (765)";
			if( ecode != sexpression::kOk ) return "sexpression::fromString didn't set error code to kOk";
			if( sexp->getType() != sexpression::kTypeParent ) return "sexpression::fromString didn't make return a parent sexpression for input (765)";
			sexpression::childIterator* ci = sexp->getChildIterator();
			if( !ci ) return "parent sexpression can't return childIterator";
			const sexpression* child = ci->borrowNextChild();
			if( !child ) return "parent sexpression has null child";
			if( child->getType() != sexpression::kTypeInt ) return "child sexpression has non-integer type - it should contain 765";
			if( child->getInt() != 765 ) return "child sexpression has wrong value";
			child = ci->borrowNextChild();
			if( !child ) return "parent sexpression only had one child";
			if( child->getType() != sexpression::kTypeString ) return "2nd child sexpression wasn't of string type";
			if( child->getString() != "STRING" ) return "2nd child had wrong string value";

			child = ci->borrowNextChild();
			if( !child ) return "parent sexpression only had two children";
			if( child->getType() != sexpression::kTypeNil ) return "3rc child sexpression wasn't of type NIL";

			child = ci->borrowNextChild();
			if( child ) return "parent sexpression had 4 children!?!";
			delete sexp;
			return NULL;
		}

		const char* getTestName() {
			return "test the static method sexpression::fromString";
		}
	};

	//
	/// This test exercises the ability of the sexpression::fromStringModify
	/// member to correctly modify strings in cases of correct S-Expressions
	/// and incorrect S-Expressions.
	//
	class testSexpressionFromStringModify : public test::basic {
	  public:
		const char* performTest() {
			util::string correct = "((NIL \"TEST\") 765)Hello, World!";
			util::string incorrect = "(((NIL))I missed a close paren";
			unsigned int ecode;

			sexpression* t = sexpression::fromStringModify( correct, ecode );
			if( !t ) return "didn't parse correct S-Expression";
			if( ecode != sexpression::kOk ) return "didn't set error code to kOk";
			if( correct != "Hello, World!" ) return "didn't leave correct string";
			delete t;

			t = sexpression::fromStringModify( incorrect, ecode );
			if( t ) return "parsed incorrect S-Expression";
			if( ecode != sexpression::kUnbalancedParens ) return "error code not set to kUnbalancedParen";
			if( incorrect != "(((NIL))I missed a close paren" ) return "modified string when parsing failed";
			return NULL;
		}

		const char* getTestName() {
			return "test the static method sexpression::fromStringModify";
		}
	};
};

void test::runnerSingleton::registerTests() {
	adoptTest( new util::testSexpressionFromString() );
	adoptTest( new util::testSexpressionFromStringModify() );
}
